//
//  EntityBase.m
//  TengineTwo
//
//  Created by StandardUser on 10/02/2012.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.

#import "EntityModel.h"
#import "CGPointExtension.h"

@interface EntityModel()

@property(readwrite, nonatomic) float sleepBoundary;
@property(readwrite, nonatomic) BOOL isTimestamped; //lazy initialisation flag for tOffset (given that tOffset could be 0 we can't test against that value)

-(void)updateDelegate;
-(void)updateCulling;
-(void)initProperties;

@end

@implementation EntityModel

@synthesize position;
@synthesize rotation;
@synthesize scale;
@synthesize cachedTag;
@synthesize type = _type;

@synthesize controller;
@synthesize updater;

@synthesize tOffset;
@synthesize speed;
@synthesize isTimestamped;

@synthesize origin;
@synthesize isVisible;
@synthesize sleepBoundary;//range either side of t when this objects update will be skipped

@synthesize isAlive = _isAlive;

#pragma mark -

-(id)initWithType:(EntityType)t {
    self = [super init];
    if (self) {
        [self initProperties];
        _type = t;
        sleepBoundary = 20;
    }
    return self;
}

- (void)dealloc {
    if(controller)  [controller release];
    if(updater)     [updater release];
    [super dealloc];
}

#pragma mark accessors

-(void)setIsVisible:(BOOL)value
{
    if(isVisible != value)
    {
        [controller hide: !isVisible Entity:self];
    }
    
    isVisible = value;
}

#pragma mark entity protocol

-(void)kill
{
    _isAlive = NO;
}

-(BOOL)isAlive
{
    return _isAlive && isVisible;
}

#pragma mark Tengine delegate

-(void)updateFromT:(float)t
{
    if(NO == isTimestamped)
    {
        tOffset = t;
        isTimestamped = YES;
    }
    
    if(updater == nil) return;
    
    if((t - tOffset) > sleepBoundary || 
       (t - tOffset) < 0)
    {
        [self setIsVisible:NO];
    }
    else
    {
        [updater update:self FromT:t];
        [self updateDelegate];
        [self updateCulling]; //will update visibility
    }
}

#pragma mark poolable protocol

-(void)clean
{
    [self initProperties];
}

#pragma mark -

-(void)initProperties
{
    position = ccp(0,0);
    rotation = 0;
    scale = 1.0;
    origin = ccp(0,0);
    
    sleepBoundary = 20;
    
    _type = UNDEFINED;
    
    //lazy initialisers
    controller =  nil;
    updater = nil;
    cachedTag = nil;
    tOffset = 0;
    speed = 0;
    isTimestamped = NO;
   
    _isAlive  = YES;
    isVisible = YES; //!!!important!!!
}

-(void)updateDelegate
{
    if(controller == nil || cachedTag == nil) return;
    
    [controller updateEntity:self];
}

//probably a cleaner way of doing this...
-(void)updateCulling
{
    if(position.x < 0 || position.x >  360 || position.y < 0 || position.y > 480) 
    {
        [self setIsVisible:NO];
    }
    else
    {   
        [self setIsVisible:YES];
    }
}

@end
